;(function(root, $) {

var UCD = root.UCD || (root.UCD = { Core: $ }), extend = $.extend;

var TEMPLATE = '<div class="ucd-waterwave">'
  + '	<div class="ucd-waterwave-canvas"></div>'
  + '	<div class="ucd-waterwave-label"></div>'
  + '</div>';

var utils = {
	indexOf: function(a, cb) {
		for (var i = 0, len = a ? a.length : 0; i < len; i++) {
			if (cb(a[i], i, a)) {
				return i;
			}
		}
		return -1;
	}, 

	buildHTML: function(n, cls, content) {
		var html = [];
		content = content || '';

		for (var i = 0; i < n; i++) {
			html.push('<div class="' + (cls + ' ' + cls + '-' + i) + '">' + content + '</div>');
		}
		return html.join('');
	},

	percents: function(a, cb) {
		var sum = 0, aa = $.map(a, function(v) {
			var val = cb(v);
			sum += val;
			return val;
		});

		return $.map(aa, function(v) {
			return v/sum;
		});
	},

	curvePointWithD: function(x, y, m, n, d) {
		// TODO: 垂直情况
		var D = d/Math.sqrt( (x-m)*(x-m) + (y-n)*(y-n) );
		return [ (x+m)/2 + (n-y)*D, (y+n)/2 + (m-x)*D ];
	},

	curvePoint2: function(x, y, m, n, xx, yy, f) {
		return [ [ m*f+x*(1-f), n*f+y*(1-f) ], [ xx*f+m*(1-f), yy*f+n*(1-f) ] ];
	},

	curvePoint: function(x, y, m, n, d) {
		// TODO: 垂直情况
		var D = d/Math.sqrt( (x-m)*(x-m) + (y-n)*(y-n) );
		return [ (x+m)/2 + (n-y)*D, (y+n)/2 + (m-x)*D ];
	},

	_curvePath: function(x, y, w, h) {
		var ret = [], p2;

		// ret.push('M', x, h/2);
		
		p2 = utils.curvePoint2(x + 0, y + h/2, x + w/4, y + 0, x + w/2, y + h/2, 0.5, 0.3);
		ret.push('Q', p2[0][0], y + 0, x + w/4, y + 0);
		ret.push('Q', p2[1][0], y + 0, x + w/2, y + h/2);
		// more
		p2 = utils.curvePoint2(x + w/2, y + h/2, x + 0.75*w, y + h, x + w, y + h/2, 0.5, 0.3);
		ret.push('Q', p2[0][0], y + h, x + 0.75*w, y + h);
		ret.push('Q', p2[1][0], y + h, x + w, y + h/2);
		
		// ret.push('L', x + w, h, 'L', x + 0, h, 'Z');

		return ret.join(' ');
	},

	curvePath: function(length, baseY, w, h, deep) {
		var x = 0, ret = [];

		ret.push('M', x, baseY+h/2);

		while(x < length) {
			ret.push( utils._curvePath(x, baseY, w, h) );
			x += w;
		}

		// ret.push('L', x-w, h, 'L', 0, h, 'Z');
		ret.push('v', deep + h/2, 'H', 0, 'Z');

		return ret.join(' ');
	},

	rectPath: function(x, y, w, h) {
		var ret = ['M', x, y, 'h', w, 'v', h, 'H', x, 'Z'];

		return ret.join(' ');
	}
};


var FX_INTERVAL = 13,
  fxNow;

function createFxNow() {
  setTimeout(function() {
    fxNow = undefined;
  }, 0);
  return (fxNow = (+new Date()));
}
function animate(options) {
  var timerId, opts = $.extend({
	  	duration: 500
	  }, options), 
	  duration = opts.duration, 
    startTime, endTime,
    easeFn = $.easing[opts.easing];

  startTime = fxNow || createFxNow();
  endTime = startTime + duration;

  var tick = function() {
    var curTime = fxNow || createFxNow(),
      remains = Math.max(0, endTime - curTime),
      temp = duration ? remains / duration : 0,
      timePercent = 1 - temp,
      percent = easeFn ? easeFn(timePercent, duration * timePercent, 0, 1, duration) : timePercent;

    if (timePercent >= 1) {
      clearInterval(timerId);
      timerId = null;

      $.isFunction(opts.onComplete) && opts.onComplete(percent, timePercent);
    } else {
      $.isFunction(opts.onProgress) && opts.onProgress(percent, timePercent);
    }
  };

  return timerId = setInterval(tick, FX_INTERVAL);
}

// TODO: 优化代码，options.progress提供回调
function animateAttr(elem, attrName, from, to, options, cb) {
	var opts = $.extend({
		onProgress: function(percent) {
			var val = from + (to - from) * percent;

			SVG.attr(elem, attrName, cb ? cb(val, percent) : val);
		}, 
		onComplete: function() {
			SVG.attr(elem, attrName, cb ? cb(to, 1) : to);
		}
	}, options);

	return animate(opts);
}

var SVG = {
	NS: 'http://www.w3.org/2000/svg', 

	_create: function(tag, parent) {
		var el = document.createElementNS(SVG.NS, tag);
		if (parent) {
			parent.appendChild(el);
		}
		return el;
	}, 

	create: function(tag, parent, attrs) {
		var el = SVG._create(tag, parent);
		if (attrs) {
			SVG.attrs(el, attrs);
		}
		return el;
	}, 

	attr: function(el, key, val) {
		el.setAttribute(key, val);
		return el;
	}, 

	attrs: function(el, props) {
		for (var key in props) {
			SVG.attr(el, key, props[key]);
		}
		return el;
	}, 

	canvas: function(parent, width, height) {
		return SVG.create('svg', parent, {
			version: '1.1', 
			width: width, 
			height: height
		});
	}, 

	defs: function(parent) {
		return SVG.create('defs', parent);
	}, 

	group: function(parent) {
		return SVG.create('g', parent);
	}, 

  /**
   * 创建渐变颜色
   * 
   * @param  {String} uid  unique id
   * @param  {String} s    渐变颜色描述字符串
   * @param  {Object} defs svg parent node, should be defs node.
   */
  gradient: function(uid, s, defs) {
      var parts = s.replace(/\-/g, ' ').split(/\s+/), 
          radial = parts.length && parts[0] === 'r', 
          type = radial ? 'radialGradient' : 'linearGradient';

      var gradient, attrs, stops;

      // 0 0 100% 100%, red 0% 1, green 50% 1, blue 100% 1
      // r 50% 50% 50% 50% 50%, red 0% 1, green 50% 1, blue 100% 1
      if (radial) {
          attrs = {
              "id": uid,
              "cx": parts[1],
              "cy": parts[2],
              "r": parts[3],
              "fx": parts[4],
              "fy": parts[5]
          };

          stops = parts.slice(6);
      } else {
          attrs = {
              "id": uid,
              "x1": parts[0],
              "y1": parts[1],
              "x2": parts[2],
              "y2": parts[3]
          };

          stops = parts.slice(4);
      }

      gradient = SVG.create(type, defs, attrs); 
      for (var i = 0, len = stops.length; i < len; i+=3) {
          SVG._stop(gradient, stops[i], stops[i+1], stops[i+2]);
      }     
  }, 

  // marker-start/mid/end
  marker: function(uid, s, color, defs) {
  	s = s || 'M 0 0 L 10 5 L 0 10 z';

  	var markerElem = SVG.create('marker', defs, {
  		id: uid, 
  		viewBox: "0 0 10 10" , 
      refX: "1",
      refY: "5", 
      markerWidth: "6" , 
      markerHeight: "6", 
      orient: "auto"
  	});

  	SVG.create('path', markerElem, { d: s, fill: color });

  	return uid;
  }, 

  /**
   * 创建渐变颜色点
   * 
   * @param  {Object} root    svg parent node
   * @param  {String} color   color
   * @param  {String} offset  offset
   * @param  {String} opacity opacity
   * @return {Object}         渐变颜色点
   */
  _stop: function(root, color, offset, opacity) {
      var attrs = {
          offset: offset,
          "stop-color": color,
          "stop-opacity": opacity
      };

      return SVG.create("stop", root, attrs);
  }, 

	path: function(parent, d) {
		return SVG.create('path', parent, {
			d: d && d.join ? d.join(' ') : d
		});
	}, 

	circle: function(parent, cx, cy, r, attrs) {
		return SVG.create('circle', parent, $.extend({
			cx: cx, 
			cy: cy, 
			r: r
		}, attrs) );
	}, 

	line: function(parent, x1, y1, x2, y2) {
		return SVG.create('line', parent, {
			x1: x1, 
			y1: y1, 
			x2: x2, 
			y2: y2
		});
	}, 

	curve: function(sx, ex, y, h) {
		var r = Math.abs(ex-sx)/2;
		// 上半圆
		// return [ 'M', sx, y, 'Q', r, y - h, ex, y ].join(' ');
		return [ 'M', sx, y, 'A', r, h, 0, 0, sx > ex ? 0 : 1, ex, y ].join(' ');
	}, 

	generate: function(n, tag, parent, attrs) {
		var ret = [];
		for (var i = 0; i < n; i++) {
			ret.push( SVG.create(tag, parent, attrs) );
		}
		return ret;
	}
};

var Animator = {
	delay: function(ms, fn, ctx) {
		clearTimeout(fn.__timer);
		return fn.__timer = setTimeout(function() {
			fn && fn.call(ctx);
		}, ms);
	}, 

	to: function(el, duration, props, delay) { 
		Animator.delay(delay, function() {
			$(el).animate(props, duration);
  	});
	}, 

	from: function(el, duration, props, delay) {
		var tprops = {};

		for (var key in props) {
			tprops[key] = $(el).css(key);
		 	$(el).css(key, props[key]);
		}
		
		Animator.to(el, duration, tprops, delay);
	}, 

	fromTo: function(el, duration, props, tprops, delay) {
		for (var key in props) {
			$(el).css(key, props[key]);
		}
		
		Animator.to(el, duration, tprops, delay);
	}, 

	staggerFrom: function(el, duration, props, delay, stagger) {
		for (var i = 0, len = el ? el.length : 0; i < len; i++) {
			Animator.from(el[i], duration, props, delay + stagger * i);
		}
	}, 

	animatePath: function(path, duration, delay, done) {
		if (path.getTotalLength) {
			var pathLength = path.getTotalLength();
	    SVG.attrs(path, {
	    	'stroke-dasharray': pathLength,
	    	'stroke-dashoffset': pathLength
	    });

    	Animator.delay(delay, function() {
    		animateAttr(path, 'stroke-dashoffset', pathLength, 0, {
	    		duration: duration,
	    		complete: function() { console.trace('c');
	    			SVG.attrs(path, {
				    	'stroke-dasharray': '',
				    	'stroke-dashoffset': ''
				    });

				    done && done(path);
	    		}
	    	});
    	});
    }
    return path;
	}
};

var __uuid = 0;
function _createID(prefix) {
    return (prefix || '') + (++__uuid);
}


/**
 * WaterWave
 *
 * WaterWave descriptions.
 * 
 * @smartueExample 基本用法 widgets/waterwave/basic.html
 * @smartueExample 完整功能 widgets/waterwave/full_features.html 
 * 
 * @memberOf UCD
 * @class WaterWave
 * 
 * @param {Object} container    组件容器
 * @param {Object} options      选项
 */
function Widget(container, options) {
	if ($.isPlainObject(container)) {
		options = container;
		container = options.container;
	}

	var opts = this.options = extend({}, Widget.defaults, options);

	if (!container) {
		container = opts.container;
	}
	
	this.$container = $(container);

	this.init();
}

Widget.defaults = {
	animation: true, 
	animationDuration: 1200, 
	value: 50, 

	MAX_VALUE: 100, 
	MIN_VALUE: 0, 

	waveCount: 2, 
	waveLength: 960, 
	waveWidth: 224, 
	waveHeight: 12,
	fillColor: 'rgba(255, 255, 255, 0.2)',
	radius: 98, 
	clipRadius: 98, 
	strokeWidth: 2, 
	strokeColor: '#fff', 

	showLabel: false, 
	onFormatLabel: function(val) { return val; }
};

extend(Widget.prototype, /** @lends UCD.WaterWave.prototype */{
	/**
	 * 初始化
	 */
	init: function() {
		return this._initSize()._create()._update()._bindEvents();
	}, 
	/**
	 * 自适应
	 */
	resize: function() {
		var opts = this.options;

		return this._initSize()._update();
	}, 
	/**
	 * 销毁
	 */
	destroy: function() {
		var opts = this.options;
	},  
	_initSize: function() {
		var $c = this.$container;

		this._width = $c.width();
		this._height = $c.height();

		return this;
	}, 

	_createClipPath: function() {
		var opts = this.options;
		var clipId = _createID('ucd_waterwave_clip_');
		var clipPath = SVG.create('clipPath', this._defs, {
			id: clipId
		});
		this._clipCircle = SVG.circle(clipPath, this._width/2, this._height/2, opts.clipRadius||opts.radius);
		return clipId;
	}, 

	_createWave: function(i) {
		var opts = this.options, ww = opts.waveWidth, wh = opts.waveHeight;
		var gPath = SVG.group(this._gWaves), path, rect;

		// TODO: IE>9, SVG不支持transform， IE8不支持SVG
		SVG.attr(gPath, 'class', 'ucd-waterwave-wave ucd-waterwave-wave-' + i);
		
		path = SVG.create('path', gPath, {
			// 'class': 'ucd-waterwave-wave', 
			d: utils.curvePath(opts.waveLength, this._height/2-wh, ww, wh, opts.radius*2), 
			fill: opts.fillColor
		});

		// rect = SVG.create('path', gPath, {
		// 	d: utils.rectPath(0, this._height/2, opts.waveLength, this._height/2), 
		// 	fill: opts.fillColor
		// });

		return {
			index: i, 
			group: gPath, 
			path: path, 
			rect: rect
		};
	}, 

	_create: function() {
		var opts = this.options;

		var $root = this.$root = $(TEMPLATE).appendTo(this.$container);
		this.$canvas = $root.children('.ucd-waterwave-canvas');
		this.$label = $root.children('.ucd-waterwave-label');

		this._canvas = SVG.canvas(this.$canvas[0], '100%', '100%');
		this._defs = SVG.defs(this._canvas);
		this._clipId = this._createClipPath();

		if (opts.fillGradient) {
			this._gradientId = _createID('ucd_waterwave_gradient_');
			this._gradient = SVG.gradient(this._gradientId, opts.fillGradient, this._defs);
			opts.fillColor = 'url(#' + this._gradientId + ')';
		}

		this._gGroup = SVG.group(this._canvas);
		this._gWaves = SVG.group(this._gGroup);
		this._gCircle = SVG.group(this._canvas);

		// TODO: 不能在this._gWaves上面clip，因为this._gWaves或transform，clip会跟随
		SVG.attr(this._gGroup, 'clip-path', 'url(#' + this._clipId + ')');

		this._waves = [];
		for (var i = 0; i < opts.waveCount; i++) {
			this._waves.push( this._createWave(i) );
		}

		// circle
		this._circle = SVG.circle(this._gCircle, this._width/2, this._height/2, opts.radius, {
			id: this._circleId, 
			'stroke-width': opts.strokeWidth, 
			stroke: opts.strokeColor,
			fill: 'none'
		});

		return this;
	},
	_update: function() {
		var self = this, opts = this.options;

		if (opts.animation) {
			var percent = (opts.value-opts.MIN_VALUE)/(opts.MAX_VALUE-opts.MIN_VALUE);
			
			// TODO: svg的transform属性没有translateX,Y子类的，只有translate(x,[y])
			animateAttr(this._gWaves, 'transform', opts.radius, opts.radius-2*opts.radius*percent, {
				duration: opts.animationDuration
			}, function(val, p) {
				opts.showLabel && self._updateLabel(p);
				return 'translate(0, ' + val + ')';
			});
		}

		return this;
	},

	_updateLabel: function(percent) { console.log(percent);
		var opts = this.options, val = opts.MIN_VALUE + (opts.value-opts.MIN_VALUE) * percent;
		this.$label.html ( opts.onFormatLabel.call(this, val) ); 

		this.$label.css({
			left: this._width/2 - this.$label.width()/2, 
			top: this._height/2 - this.$label.height()/2
		})
	}, 

	_bindEvents: function() {
		var self = this, opts = this.options;
	}
});

UCD.WaterWave = Widget;

})(this, jQuery);

